# @Author: 唐奇才
# @Time: 2021/6/8 16:38
# @File: 13.使用DBSCAN对红酒类型聚类.py
# @Software: PyCharm

# encoding:utf-8
import matplotlib.pyplot as plt
import pandas as pd
import math
import numpy as np
import pylab as pl

file = (open('./data/wine.csv', 'r'))
data = pd.read_csv(file)

# 这里的代码不可以用了
# dataset=[(data.ix[i,'Alcohol'], data.ix[i, 'diluted']) for i in range(0, len(data)-1, 1)]
# dataset = pd.DataFrame(pd.concat([data.loc[:, 'Alcohol'], data.loc[:, 'diluted']], axis=1))
# np.array(dataset)
# print(dataset)
x, y = data.loc[:, 'Alcohol'], data.loc[:, 'diluted']
dataset = [*zip(x, y)]
# print(dataset)
# 计算欧几里得距离,a,b分别为两个元组
def dist(a, b):
    return math.sqrt(math.pow(a[0] - b[0], 2) + math.pow(a[1] - b[1], 2))


# 算法模型
def DBSCAN(D, e, Minpts):
    # 初始化核心对象集合T,聚类个数k,聚类集合C, 未访问集合P,
    T = set()
    k = 0
    C = []
    P = set(D)
    for d in D:
        if len([i for i in D if dist(d, i) <= e]) >= Minpts:
            T.add(d)
    # 开始聚类
    while len(T):
        P_old = P
        o = list(T)[np.random.randint(0, len(T))]
        P = P - set(o)
        Q = []
        Q.append(o)
        while len(Q):
            q = Q[0]
            Nq = [i for i in D if dist(q, i) <= e]
            if len(Nq) >= Minpts:
                S = P & set(Nq)
                Q += (list(S))
                P = P - S
            Q.remove(q)
        k += 1
        Ck = list(P_old - P)
        T = T - set(Ck)
        C.append(Ck)
    return C


# 画图
def draw(C):
    colValue = ['r', 'y', 'g', 'b', 'c', 'k', 'm']
    for i in range(len(C)):
        coo_X = []  # x坐标列表
        coo_Y = []  # y坐标列表
        for j in range(len(C[i])):
            coo_X.append(C[i][j][0])
            coo_Y.append(C[i][j][1])
        pl.scatter(coo_X, coo_Y, marker='x', color=colValue[i % len(colValue)], label=i)
    pl.legend(loc='upper right')
    pl.show()


C = DBSCAN(dataset, 0.05, 6)
draw(C)
